package blue.base.internal.core.http;

import blue.base.core.http.HttpClient;
import blue.base.core.http.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.time.Duration;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * @author Jin Zheng
 * @since 2021-07-02
 */
public class DefaultHttpClientBuilder implements HttpClientBuilder {
    private static Logger logger = LoggerFactory.getLogger(DefaultHttpClientBuilder.class);

    private String id;
    private String baseUrl;
    private int timeout;
    private String username;
    private String password;
    private String proxy;
    private Map<String, String> defaultHeaders;
    private Executor executor;

    private java.net.http.HttpClient httpClient;

	public DefaultHttpClientBuilder() {
	}

    @Override
    public HttpClient build() {
	    this.init();
        DefaultHttpClient client = new DefaultHttpClient(this);
        return client;
    }

    private void init() {
        java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder();
        if (timeout > 0) {
            builder.connectTimeout(Duration.ofMillis(timeout));
        }
        if (proxy != null && !proxy.isEmpty()) {
            String[] proxys = proxy.split(":");
            if (proxys.length != 2) {
                throw new IllegalArgumentException("Invalid proxy: " + proxy);
            }

            builder.proxy(ProxySelector.of(new InetSocketAddress(proxys[0], Integer.parseInt(proxys[1]))));
        }
        if (executor != null) {
            builder.executor(executor);
        }
        if (defaultHeaders == null) {
            defaultHeaders = new HashMap<>();
        }
        if (username != null && !username.isEmpty() && password != null && !password.isEmpty()) {
            defaultHeaders.put("Authorization", this.authorization());
        }
        this.httpClient = builder.build();
        logger.info("Initialize HttpClient, id: {}, baseUrl: {}, timeout: {}ms, proxy: {}, username: {}, password: {}," +
                " defaultHeaders: {}", id, baseUrl, timeout, proxy, username, password, defaultHeaders);
    }

    private String authorization() {
        String auth = username + ":" + password;
        return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
    }

    @Override
    public HttpClientBuilder setId(String id) {
	    this.id = id;
        return this;
    }

    @Override
    public HttpClientBuilder setBaseUrl(String baseUrl) {
	    this.baseUrl = baseUrl;
        return this;
    }

    @Override
    public HttpClientBuilder setTimeout(int timeout) {
	    this.timeout = timeout;
        return this;
    }

    @Override
    public HttpClientBuilder setUsername(String username) {
	    this.username = username;
        return this;
    }

    @Override
    public HttpClientBuilder setPassword(String password) {
	    this.password = password;
        return this;
    }

    @Override
    public HttpClientBuilder setProxy(String proxy) {
	    this.proxy = proxy;
        return this;
    }

    @Override
    public HttpClientBuilder setDefaultHeaders(Map<String, String> headers) {
	    this.defaultHeaders = headers;
        return this;
    }

    @Override
    public HttpClientBuilder setExecutor(Executor executor) {
	    this.executor = executor;
        return this;
    }

    public String getId() {
        return id;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public int getTimeout() {
        return timeout;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public String getProxy() {
        return proxy;
    }

    public Map<String, String> getDefaultHeaders() {
        return defaultHeaders;
    }

    public Executor getExecutor() {
        return executor;
    }

    public java.net.http.HttpClient getHttpClient() {
        return httpClient;
    }
}
